//Trie（发音类似 "try"）或者说 前缀树 是一种树形数据结构，用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景，例如自动补完和拼
//写检查。 
//
// 请你实现 Trie 类： 
//
// 
// Trie() 初始化前缀树对象。 
// void insert(String word) 向前缀树中插入字符串 word 。 
// boolean search(String word) 如果字符串 word 在前缀树中，返回 true（即，在检索之前已经插入）；否则，返回 
//false 。 
// boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ，返回 true ；否
//则，返回 false 。 
// 
//
// 
//
// 示例： 
//
// 
//输入
//["Trie", "insert", "search", "search", "startsWith", "insert", "search"]
//[[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]
//输出
//[null, null, true, false, true, null, true]
//
//解释
//Trie trie = new Trie();
//trie.insert("apple");
//trie.search("apple");   // 返回 True
//trie.search("app");     // 返回 False
//trie.startsWith("app"); // 返回 True
//trie.insert("app");
//trie.search("app");     // 返回 True
// 
//
// 
//
// 提示： 
//
// 
// 1 <= word.length, prefix.length <= 2000 
// word 和 prefix 仅由小写英文字母组成 
// insert、search 和 startsWith 调用次数 总计 不超过 3 * 10⁴ 次 
// 
//
// Related Topics 设计 字典树 哈希表 字符串 👍 1513 👎 0


package LeetCode.editor.cn;

/**
 * @author ldltd
 * @date 2023-08-25 00:54:39
 * @description 208.实现 Trie (前缀树)
 */
public class ImplementTriePrefixTree{
	 public static void main(String[] args) {


	 }
	 
//力扣代码
//leetcode submit region begin(Prohibit modification and deletion)
class Trie1 {
		 int N=100010;
		 //子树
		 int [][]son;
		 //当前节点结束的单词数
		 int []cnt;
		 //用到的下标，0是根节点
		 int idx;
    public Trie1() {
			this.son=new int[N][26];
			this.cnt=new int[N];
    }

    public void insert(String word) {
		int p=0;
		for (int i = 0; i < word.length(); i++) {
			int u=word.charAt(i)-'a';
			if(son[p][u]==0){
				son[p][u]=++idx;
			}
			p=son[p][u];
		}
		cnt[p]++;
    }

    public boolean search(String word) {
		int p=0;
		for (int i = 0; i < word.length(); i++) {
			int u=word.charAt(i)-'a';
			if(son[p][u]==0) return false;
			p=son[p][u];
		}
		if(cnt[p]>0) return true;
		return false;
    }

    public boolean startsWith(String prefix) {
		int p=0;
		for (int i = 0; i < prefix.length(); i++) {
			int u=prefix.charAt(i)-'a';
			if(son[p][u]==0) return false;
			p=son[p][u];
		}
		return true;

    }
}

class Trie{
		 private Trie[] son;
		 private boolean end;
		 public Trie(){
			 son=new Trie[26];
			 end=false;
		 }
		 public void insert(String word){
			 Trie node=this;
			 for (int i = 0; i < word.length(); i++) {
				 char c = word.charAt(i);
				 int index=c-'a';
				 if(node.son[index]==null){
					 node.son[index]=new Trie();
				 }
				 node=node.son[index];
			 }
			 node.end=true;
		 }

		 public boolean search(String word){
			 Trie node=searchPrefix(word);
			 return node!=null&& node.end;
		 }
		 public boolean startsWith(String prefix){
			 return searchPrefix(prefix)!=null;
		 }
		 private Trie searchPrefix(String prefix){
			 Trie node=this;
			 for (int i = 0; i < prefix.length(); i++) {
				 char c = prefix.charAt(i);
				 int ind=c-'a';
				 if(node.son[ind]==null){
					 return null;
				 }
				 node=node.son[ind];
			 }
			 return node;
		 }
}

/**
 * Your Trie object will be instantiated and called as such:
 * Trie obj = new Trie();
 * obj.insert(word);
 * boolean param_2 = obj.search(word);
 * boolean param_3 = obj.startsWith(prefix);
 */
//leetcode submit region end(Prohibit modification and deletion)

}
